/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.apache.ignite.ml.util.generators.primitives.scalar;

import java.util.Arrays;
import java.util.function.Supplier;
import java.util.stream.IntStream;
import org.apache.ignite.internal.util.typedef.internal.A;
import org.apache.ignite.ml.math.functions.IgniteFunction;
import org.apache.ignite.ml.math.primitives.vector.Vector;
import org.apache.ignite.ml.math.primitives.vector.VectorUtils;
import org.apache.ignite.ml.util.generators.primitives.vector.VectorGenerator;

/**
 * Represents a generator of pseudo-random scalar values.
 */
public interface RandomProducer extends Supplier<Double> {
    /**
     * Create {@link VectorGenerator} with vectors having feature values generated by random producer.
     *
     * @param vectorSize Generated vector size.
     * @return Vector generator.
     */
    public default VectorGenerator vectorize(int vectorSize) {
        return () -> VectorUtils.of(IntStream.range(0, vectorSize).mapToDouble(x -> get()).toArray());
    }

    /**
     * Adds value generated by random producer to function value.
     *
     * @param f Function.
     * @return New function with noize.
     */
    public default IgniteFunction<Double, Double> noizify(IgniteFunction<Double, Double> f) {
        return t -> f.apply(t) + get();
    }

    /**
     * Adds values generated by random producer to each vector value.
     *
     * @param vector Vector.
     * @return New vector.
     */
    public default Vector noizify(Vector vector) {
        Vector cp = vector.copy();
        for (int i = 0; i < vector.size(); i++)
            cp.set(i, cp.get(i) + get());
        return cp;
    }

    /**
     * Creates {@link VectorGenerator} with vectors having feature values in according to
     * preudorandom producers.
     *
     * @param producers Feature value producers.
     * @return Vector generator.
     */
    public static VectorGenerator vectorize(RandomProducer... producers) {
        A.notEmpty(producers, "producers");

        return () -> VectorUtils.of(Arrays.stream(producers).mapToDouble(Supplier::get).toArray());
    }
}
